#include <qmediaplayer.h>
#include <qmediacontent.h>
#include <qfileinfo.h>

#include "MediaEngine.h"
#include "MediaListModel.h"
#include "supported_files.h"



/** @class MediaEngine
 *
 * This file implements playback operations for a media with
 * specific plugin. In this specific implementation, Qt multimedia
 * module is used.
 */

/**
 * setup all media objects connections and make internal connections
 */
MediaEngine::MediaEngine( QObject *parent) :
   IF_MediaEngineInterface(parent)
{
   m_player.setVideoOutput( &m_videoWidget);

   connect( &m_player, SIGNAL(stateChanged(QMediaPlayer::State)),
            this, SLOT(onStateChanged(QMediaPlayer::State)) );
   connect( &m_player, SIGNAL(volumeChanged(int)),
            this, SLOT(onVolumeChanged(int)) );
   connect( &m_player, SIGNAL(durationChanged(qint64)),
            this, SIGNAL(totalTimeChanged(qint64)) );
   connect( &m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
            this, SLOT(onMediaStatusChanged(QMediaPlayer::MediaStatus)) );
   connect( &m_player, SIGNAL(videoAvailableChanged(bool)),
            this, SIGNAL(videoAvailableChanged(bool)) );
   connect( &m_player, SIGNAL(currentMediaChanged(QMediaContent)),
            &m_videoWidget, SLOT(onMediaChanged()) );

   connect( &m_player, SIGNAL(stateChanged(QMediaPlayer::State)),
            &m_videoWidget, SLOT(onStateChanged(QMediaPlayer::State)) );
   connect( &m_player, SIGNAL(videoAvailableChanged(bool)),
            &m_videoWidget, SLOT(onVideoAvailableChanged(bool)) );

   /* media position changed during playback */
   connect( &m_player, SIGNAL(positionChanged(qint64)),
            this, SIGNAL(tick(qint64)) );
}

MediaEngine::~MediaEngine()
{
}

void MediaEngine::setCurrentSource(const AbstractMediaSource *source)
{
   if (source != NULL)
   {
      QMediaContent content = source->mediaContent().value<QMediaContent>();
      m_player.setMedia( content );
   }
   else
   {
      /* no active source */
      m_player.setMedia( QMediaContent() );
   }
}

void MediaEngine::play()
{
   m_player.play();
}

void MediaEngine::pause()
{
   m_player.pause();
}

void MediaEngine::togglePlayPause()
{
   if (m_player.state() == QMediaPlayer::PlayingState)
   {
      pause();
   }
   else
   {
      /* paused or stopped */
      play();
   }
}

void MediaEngine::stop()
{
   m_player.stop();
}

/** bring track back at beginning */
void MediaEngine::rewind()
{
   onUserPositionRequested(0);
   m_player.pause();
}

void MediaEngine::onUserPositionRequested( qint64 positionMs)
{
   /* PATCH. It seems that setting the position of a paused media
    *   has the effect of starting playback. For this reason a
    *   work around is needed. */
   if (m_player.state() != QMediaPlayer::PausedState)
   {
      /* default behaviour */
      m_player.setPosition( positionMs);
      m_playbackStartPosition = NO_CHANGE_PLAYBACK;
   }
   else
   {
      m_playbackStartPosition = positionMs;
      /* keep system aligned to this position */
      emit tick( positionMs);
   }
}

void MediaEngine::setMuted(bool isMuted)
{
   m_player.setMuted( isMuted);
   emit muteStatus( isMuted);
}

void MediaEngine::setVolume(int vol)
{
   m_player.setVolume( vol );
}

int MediaEngine::volume()
{
   return  m_player.volume();
}

/** convert Qt multimedia volume into application volume */
void MediaEngine::onVolumeChanged(int localVolume)
{
   /* in this case, volume has the same scale */
   emit volumeChanged( localVolume );
}

void MediaEngine::setTickInterval( qint32 tickMs )
{
   m_player.setNotifyInterval( tickMs );
}

/** called on change of loading status of the media */
void MediaEngine::onMediaStatusChanged(QMediaPlayer::MediaStatus newStatus)
{
   if (newStatus == QMediaPlayer::EndOfMedia)
   {
      emit finished();
   }
   else if (newStatus == QMediaPlayer::LoadedMedia)
   {
      emit stateChanged( AudioObject::PausedState);
   }
   else if (newStatus == QMediaPlayer::BufferedMedia)
   {
      /* player state can be 'playing' or 'paused' */
      if (m_player.state() == QMediaPlayer::PlayingState)
      {
         emit stateChanged( AudioObject::PlayingState);
      }
      else
      {
         emit stateChanged( AudioObject::PausedState);
      }
   }
   else
   {
      /* media not ready to be played-back */
      emit stateChanged( AudioObject::LoadingState);
   }
}

/** called on change of playing status of player.
 * Converts Qt multimedia states into pulgin-independent
 * AudioObject states.
 */
void MediaEngine::onStateChanged(QMediaPlayer::State newState)
{
   switch (newState)
   {
   case QMediaPlayer::PlayingState:
      /* PATCH: update position if needed */
      if (m_playbackStartPosition != NO_CHANGE_PLAYBACK)
      {
         m_player.setPosition( m_playbackStartPosition);
         m_playbackStartPosition = NO_CHANGE_PLAYBACK;
      }

      emit stateChanged( AudioObject::PlayingState );
      break;
   case QMediaPlayer::PausedState:
      emit stateChanged( AudioObject::PausedState );
      break;
   case QMediaPlayer::StoppedState:
      emit stateChanged( AudioObject::StoppedState );
      break;
   default:
      break;
   }
}

/** @return the playing state of the current active object */
AudioObject::State MediaEngine::state()
{
   AudioObject::State state;

   switch (m_player.state())
   {
   case QMediaPlayer::StoppedState:
      state = AudioObject::StoppedState;
      break;
   case QMediaPlayer::PlayingState:
      state = AudioObject::PlayingState;
      break;
   case QMediaPlayer::PausedState:
      state = AudioObject::PausedState;
      break;
   default:
      state = AudioObject::ErrorState;
      break;
   }

   return state;
}

